// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu
#pragma once

#include <algorithm>
#include <cmath>
#include <vector>

#include "coin2/base/log.h"

namespace coin2::strategy::pta::performance {

double mean(const std::vector<double>& arr) {
  double sum = std::accumulate(std::begin(arr), std::end(arr), 0.0);
  double mean = sum / arr.size();
  return mean;
}

double stddev(const std::vector<double>& arr) {
  CHECK_GT_THROW(arr.size(), 1);

  double avg = mean(arr);
  double accum = 0.0;
  std::for_each(std::begin(arr), std::end(arr), [&](const double x) {
    accum += (x - avg) * (x - avg);
  });

  double sd = std::sqrt(accum / (arr.size() - 1));
  return sd;
}

double sharpe(const std::vector<double>& pnls, double eps = 1e-6) {
  if (pnls.size() < 2) {
    return 0;
  }
  return mean(pnls) / (stddev(pnls) + eps);
}

double sortino(const std::vector<double>& pnls, double target = 0, double eps = 1e-6) {
  if (pnls.size() < 2) {
    return 0;
  }
  double downside = 0;
  for (const auto& pnl : pnls) {
    double d = std::min(target, pnl - target);
    downside += d * d;
  }
  double tdd = std::sqrt(downside / pnls.size());
  return (mean(pnls) - target) / (tdd + eps);
}

double profit_factor(const std::vector<double>& pnls, double eps = 1e-6) {
  if (pnls.size() < 2) {
    return 0;
  }
  double profit = 0;
  double loss = 0;
  for (const auto& pnl : pnls) {
    if (pnl > 0) {
      profit += pnl;
    } else {
      loss += -pnl;
    }
  }
  return profit / (loss + eps);
}

}  // namespace coin2::strategy::pta::performance
